package com.iris.live.services.report.data.formulars;

import com.iris.live.services.data.models.ReportConfig;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description:使用Groovy执行公式
 * @author: Tony.Zhang
 * @Date: 2017-08-23 17:46
 **/
public class GroovyFormular implements IFormular {
    private static Map <String,Script> scriptMap = new ConcurrentHashMap<>();

    private static Logger logger = LoggerFactory.getLogger(GroovyFormular.class);

    public static Script createScript(String scriptName) throws Exception {
        try {
            if (scriptMap.containsKey(scriptName)) {
                return scriptMap.get(scriptName);
            } else {
                Script script = new GroovyShell().parse(scriptName);
                scriptMap.put(scriptName, script);
                return script;
            }
        }catch(Exception exc){
            logger.error(scriptName, exc);
            throw exc;
        }
    }

    @Override
    public double getValue(ReportConfig config, String dimension, Map<String, Map> datas) throws Exception {
        String expression = config.getFormularExpression(), bindingValue;
        Double value;
        expression = expression.replace("{unit}", dimension.replace("/", "//").replace(" ", "_").replace(".", "_").replace("（","_").replace("）","_").replace("(", "_").replace(")", "_"));
        expression = expression.substring(expression.indexOf("(") + 1, expression.lastIndexOf(")")).replace(" ","").replace("，","");  // 去除表达式变量中的空格
        String [] elemrnts=expression.split("[+]|[-]|[*]|[/]|[(]|[)]");
        expression = ("result = " + expression + "; return result");

        Script script=createScript(expression);

        Binding binding = new Binding();
        Set<String> keys = datas.keySet();
        for (String temp:elemrnts){//优先置 0.
            temp = temp.replace("//","/");
            if(temp.isEmpty()){
                continue;
            }
            if(keys.contains(temp)){
                if(datas.get(temp).get(config.getCategory()+"Value") == null){
                    logger.warn("no key found for {}", config.getCategory()+"Value");

                }else {
                    binding.setVariable(temp.replace(" ", "").replace("，", ""), Double.valueOf(datas.get(temp).get(config.getCategory() + "Value").toString()));
                }
            }
            else{
            binding.setVariable(temp.replace(" ","").replace("，",""), 0d);}
        }

        String expKey = null;
        for(String key : keys){
            if(key.endsWith(dimension)){
                expKey = key.replace("/", "//").replace(" ", "_").replace(".", "_").replace("（","_").replace("）","_").replace("(", "_").replace(")", "_");

                if(datas.get(key).get(config.getCategory()+"Value") == null) {
                    binding.setVariable(expKey, 0);
                    continue;
                }

                bindingValue = datas.get(key).get(config.getCategory()+"Value").toString();
                if(bindingValue.endsWith("%")){
                    bindingValue = bindingValue.substring(0, bindingValue.indexOf("%"));
                    value = Double.valueOf(bindingValue)/100;
                }else{
                    value = Double.valueOf(bindingValue);
                }

                // 去除表达式变量中的空格
                binding.setVariable(expKey, value);
            }
        }

        value= (Double) InvokerHelper.createScript(script.getClass(), binding).run();
        if(value.isNaN()||value.isInfinite()){
            return 0;
        }else{
            return value.doubleValue();
        }
    }

    public static void main(String[] args){
        String exp = "result=金融漏斗_含有金融报价数_A6_FBU_allroad / 金融漏斗_进店线索数_A6_FBU_allroad; return result";

        Binding binding = new Binding();

        binding.setVariable("金融漏斗_含有金融报价数_A6_FBU_allroad",10);

        binding.setVariable("金融漏斗_进店线索数_A6_FBU_allroad", 2);

        GroovyShell shell = new GroovyShell(binding);

        Object value =shell.evaluate (exp);


    }


}